home *** CD-ROM | disk | FTP | other *** search
/ Isometric Game Programming with DirectX 7.0 / Isometric Game Programming.iso / directx / dxf / samples / multimedia / directinput / joystick / joystick.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-04  |  13.2 KB  |  374 lines

  1. //-----------------------------------------------------------------------------
  2. // File: Joystick.cpp
  3. //
  4. // Desc: Demonstrates an application which receives immediate 
  5. //       joystick data in exclusive mode via a dialog timer.
  6. //
  7. // Copyright (c) 1998-2000 Microsoft Corporation. All rights reserved.
  8. //-----------------------------------------------------------------------------
  9. #define STRICT
  10. #include <windows.h>
  11. #include <basetsd.h>
  12. #include <dinput.h>
  13. #include "resource.h"
  14.  
  15.  
  16.  
  17.  
  18. //-----------------------------------------------------------------------------
  19. // Function-prototypes
  20. //-----------------------------------------------------------------------------
  21. INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  22. BOOL CALLBACK    EnumAxesCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext );
  23. BOOL CALLBACK    EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* pContext );
  24. HRESULT InitDirectInput( HWND hDlg );
  25. VOID    FreeDirectInput();
  26. HRESULT UpdateInputState( HWND hDlg );
  27.  
  28.  
  29.  
  30.  
  31. //-----------------------------------------------------------------------------
  32. // Defines, constants, and global variables
  33. //-----------------------------------------------------------------------------
  34. #define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } }
  35. #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
  36.  
  37. LPDIRECTINPUT8       g_pDI              = NULL;         
  38. LPDIRECTINPUTDEVICE8 g_pJoystick        = NULL;     
  39. DIDEVCAPS            g_diDevCaps;
  40.  
  41.  
  42.  
  43.  
  44. //-----------------------------------------------------------------------------
  45. // Name: WinMain()
  46. // Desc: Entry point for the application.  Since we use a simple dialog for 
  47. //       user interaction we don't need to pump messages.
  48. //-----------------------------------------------------------------------------
  49. int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, int )
  50. {
  51.     // Display the main dialog box.
  52.     DialogBox( hInst, MAKEINTRESOURCE(IDD_JOYST_IMM), NULL, MainDlgProc );
  53.     
  54.     return TRUE;
  55. }
  56.  
  57.  
  58.  
  59.  
  60. //-----------------------------------------------------------------------------
  61. // Name: MainDialogProc
  62. // Desc: Handles dialog messages
  63. //-----------------------------------------------------------------------------
  64. INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  65. {
  66.     switch( msg ) 
  67.     {
  68.         case WM_INITDIALOG:
  69.             if( FAILED( InitDirectInput( hDlg ) ) )
  70.             {
  71.                 MessageBox( NULL, "Error Initializing DirectInput", 
  72.                             "DirectInput Sample", MB_ICONERROR | MB_OK );
  73.                 EndDialog( hDlg, 0 );
  74.             }
  75.  
  76.             // Set a timer to go off 30 times a second. At every timer message
  77.             // the input device will be read
  78.             SetTimer( hDlg, 0, 1000 / 30, NULL );
  79.             return TRUE;
  80.  
  81.         case WM_ACTIVATE:
  82.             if( WA_INACTIVE != wParam && g_pJoystick )
  83.             {
  84.                 // Make sure the device is acquired, if we are gaining focus.
  85.                 g_pJoystick->Acquire();
  86.             }
  87.             return TRUE;
  88.  
  89.         case WM_TIMER:
  90.             // Update the input device every timer message
  91.             if( FAILED( UpdateInputState( hDlg ) ) )
  92.             {
  93.                 KillTimer( hDlg, 0 );    
  94.                 MessageBox( NULL, "Error Reading Input State. "
  95.                             "The sample will now exit.", "DirectInput Sample", 
  96.                             MB_ICONERROR | MB_OK );
  97.                 EndDialog( hDlg, TRUE ); 
  98.             }
  99.             return TRUE;
  100.  
  101.         case WM_COMMAND:
  102.             switch( LOWORD(wParam) )
  103.             {
  104.                 case IDCANCEL:
  105.                     KillTimer( hDlg, 0 );    
  106.                     FreeDirectInput();    
  107.                     EndDialog( hDlg, 0 );
  108.                     return TRUE;
  109.             }
  110.     }
  111.  
  112.     return FALSE; // Message not handled 
  113. }
  114.  
  115.  
  116.  
  117.  
  118. //-----------------------------------------------------------------------------
  119. // Name: InitDirectInput()
  120. // Desc: Initialize the DirectInput variables.
  121. //-----------------------------------------------------------------------------
  122. HRESULT InitDirectInput( HWND hDlg )
  123. {
  124.     HRESULT hr;
  125.  
  126.     // Register with the DirectInput subsystem and get a pointer
  127.     // to a IDirectInput interface we can use.
  128.     // Create a DInput object
  129.     if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, 
  130.                                          IID_IDirectInput8, (VOID**)&g_pDI, NULL ) ) )
  131.         return hr;
  132.  
  133.     // Look for a simple joystick we can use for this sample program.
  134.     if( FAILED( hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, 
  135.                                          EnumJoysticksCallback,
  136.                                          NULL, DIEDFL_ATTACHEDONLY ) ) )
  137.         return hr;
  138.  
  139.     // Make sure we got a joystick
  140.     if( NULL == g_pJoystick )
  141.     {
  142.         MessageBox( NULL, "Joystick not found. The sample will now exit.", 
  143.                     "DirectInput Sample", 
  144.                     MB_ICONERROR | MB_OK );
  145.         EndDialog( hDlg, 0 );
  146.         return S_OK;
  147.     }
  148.  
  149.     // Set the data format to "simple joystick" - a predefined data format 
  150.     //
  151.     // A data format specifies which controls on a device we are interested in,
  152.     // and how they should be reported. This tells DInput that we will be
  153.     // passing a DIJOYSTATE2 structure to IDirectInputDevice::GetDeviceState().
  154.     if( FAILED( hr = g_pJoystick->SetDataFormat( &c_dfDIJoystick2 ) ) )
  155.         return hr;
  156.  
  157.     // Set the cooperative level to let DInput know how this device should
  158.     // interact with the system and with other DInput applications.
  159.     if( FAILED( hr = g_pJoystick->SetCooperativeLevel( hDlg, DISCL_EXCLUSIVE | 
  160.                                                              DISCL_FOREGROUND ) ) )
  161.         return hr;
  162.  
  163.     // Determine how many axis the joystick has (so we don't error out setting
  164.     // properties for unavailable axis)
  165.     g_diDevCaps.dwSize = sizeof(DIDEVCAPS);
  166.     if ( FAILED( hr = g_pJoystick->GetCapabilities(&g_diDevCaps) ) )
  167.         return hr;
  168.  
  169.     // Enumerate the axes of the joyctick and set the range of each axis. Note:
  170.     // we could just use the defaults, but we're just trying to show an example
  171.     // of enumerating device objects (axes, buttons, etc.).
  172.     if ( FAILED( hr = g_pJoystick->EnumObjects( EnumAxesCallback, 
  173.                                                 (VOID*)hDlg, DIDFT_AXIS ) ) )
  174.         return hr;
  175.  
  176.     return S_OK;
  177. }
  178.  
  179.  
  180.  
  181.  
  182. //-----------------------------------------------------------------------------
  183. // Name: EnumJoysticksCallback()
  184. // Desc: Called once for each enumerated joystick. If we find one, create a
  185. //       device interface on it so we can play with it.
  186. //-----------------------------------------------------------------------------
  187. BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance,
  188.                                      VOID* pContext )
  189. {
  190.     HRESULT hr;
  191.  
  192.     // Obtain an interface to the enumerated joystick.
  193.     hr = g_pDI->CreateDevice( pdidInstance->guidInstance, &g_pJoystick, NULL );
  194.  
  195.     // If it failed, then we can't use this joystick. (Maybe the user unplugged
  196.     // it while we were in the middle of enumerating it.)
  197.     if( FAILED(hr) ) 
  198.         return DIENUM_CONTINUE;
  199.  
  200.     // Stop enumeration. Note: we're just taking the first joystick we get. You
  201.     // could store all the enumerated joysticks and let the user pick.
  202.     return DIENUM_STOP;
  203. }
  204.  
  205.  
  206.  
  207.  
  208. //-----------------------------------------------------------------------------
  209. // Name: EnumAxesCallback()
  210. // Desc: Callback function for enumerating the axes on a joystick
  211. //-----------------------------------------------------------------------------
  212. BOOL CALLBACK EnumAxesCallback( const DIDEVICEOBJECTINSTANCE* pdidoi,
  213.                                 VOID* pContext )
  214. {
  215.     HWND hDlg = (HWND)pContext;
  216.  
  217.     DIPROPRANGE diprg; 
  218.     diprg.diph.dwSize       = sizeof(DIPROPRANGE); 
  219.     diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); 
  220.     diprg.diph.dwHow        = DIPH_BYID; 
  221.     diprg.diph.dwObj        = pdidoi->dwType; // Specify the enumerated axis
  222.     diprg.lMin              = -1000; 
  223.     diprg.lMax              = +1000; 
  224.     
  225.     // Set the range for the axis
  226.     if( FAILED( g_pJoystick->SetProperty( DIPROP_RANGE, &diprg.diph ) ) )
  227.         return DIENUM_STOP;
  228.  
  229.     // Set the UI to reflect what axes the joystick supports
  230.     if (pdidoi->guidType == GUID_XAxis)
  231.     {
  232.         EnableWindow( GetDlgItem( hDlg, IDC_X_AXIS ), TRUE );
  233.         EnableWindow( GetDlgItem( hDlg, IDC_X_AXIS_TEXT ), TRUE );
  234.     }
  235.     if (pdidoi->guidType == GUID_YAxis)
  236.     {
  237.         EnableWindow( GetDlgItem( hDlg, IDC_Y_AXIS ), TRUE );
  238.         EnableWindow( GetDlgItem( hDlg, IDC_Y_AXIS_TEXT ), TRUE );
  239.     }
  240.     if (pdidoi->guidType == GUID_ZAxis)
  241.     {
  242.         EnableWindow( GetDlgItem( hDlg, IDC_Z_AXIS ), TRUE );
  243.         EnableWindow( GetDlgItem( hDlg, IDC_Z_AXIS_TEXT ), TRUE );
  244.     }
  245.     if (pdidoi->guidType == GUID_RxAxis)
  246.     {
  247.         EnableWindow( GetDlgItem( hDlg, IDC_X_ROT ), TRUE );
  248.         EnableWindow( GetDlgItem( hDlg, IDC_X_ROT_TEXT ), TRUE );
  249.     }
  250.     if (pdidoi->guidType == GUID_RyAxis)
  251.     {
  252.         EnableWindow( GetDlgItem( hDlg, IDC_Y_ROT ), TRUE );
  253.         EnableWindow( GetDlgItem( hDlg, IDC_Y_ROT_TEXT ), TRUE );
  254.     }
  255.     if (pdidoi->guidType == GUID_RzAxis)
  256.     {
  257.         EnableWindow( GetDlgItem( hDlg, IDC_Z_ROT ), TRUE );
  258.         EnableWindow( GetDlgItem( hDlg, IDC_Z_ROT_TEXT ), TRUE );
  259.     }
  260.     if (pdidoi->guidType == GUID_Slider)
  261.     {
  262.         EnableWindow( GetDlgItem( hDlg, IDC_SLIDER0 ), TRUE );
  263.         EnableWindow( GetDlgItem( hDlg, IDC_SLIDER0_TEXT ), TRUE );
  264.         EnableWindow( GetDlgItem( hDlg, IDC_SLIDER1 ), TRUE );
  265.         EnableWindow( GetDlgItem( hDlg, IDC_SLIDER1_TEXT ), TRUE );
  266.     }
  267.  
  268.     return DIENUM_CONTINUE;
  269. }
  270.  
  271.  
  272.  
  273.  
  274. //-----------------------------------------------------------------------------
  275. // Name: UpdateInputState()
  276. // Desc: Get the input device's state and display it.
  277. //-----------------------------------------------------------------------------
  278. HRESULT UpdateInputState( HWND hDlg )
  279. {
  280.     HRESULT     hr;
  281.     CHAR        strText[128]; // Device state text
  282.     DIJOYSTATE2 js;           // DInput joystick state 
  283.     CHAR*       str;
  284.  
  285.     if( NULL == g_pJoystick ) 
  286.         return S_OK;
  287.  
  288.     // Poll the device to read the current state
  289.     hr = g_pJoystick->Poll(); 
  290.     if( FAILED(hr) )  
  291.     {
  292.         // DInput is telling us that the input stream has been
  293.         // interrupted. We aren't tracking any state between polls, so
  294.         // we don't have any special reset that needs to be done. We
  295.         // just re-acquire and try again.
  296.         hr = g_pJoystick->Acquire();
  297.         while( hr == DIERR_INPUTLOST ) 
  298.             hr = g_pJoystick->Acquire();
  299.  
  300.         // hr may be DIERR_OTHERAPPHASPRIO or other errors.  This
  301.         // may occur when the app is minimized or in the process of 
  302.         // switching, so just try again later 
  303.         return S_OK; 
  304.     }
  305.  
  306.     // Get the input's device state
  307.     if( FAILED( hr = g_pJoystick->GetDeviceState( sizeof(DIJOYSTATE2), &js ) ) )
  308.         return hr; // The device should have been acquired during the Poll()
  309.  
  310.     // Display joystick state to dialog
  311.     wsprintf( strText, "%ld", js.lX ); 
  312.     SetWindowText( GetDlgItem( hDlg, IDC_X_AXIS ), strText );
  313.     wsprintf( strText, "%ld", js.lY ); 
  314.     SetWindowText( GetDlgItem( hDlg, IDC_Y_AXIS ), strText );
  315.     wsprintf( strText, "%ld", js.lZ ); 
  316.     SetWindowText( GetDlgItem( hDlg, IDC_Z_AXIS ), strText );
  317.  
  318.     // For steering wheels
  319.     wsprintf( strText, "%ld", js.lRx ); 
  320.     SetWindowText( GetDlgItem( hDlg, IDC_X_ROT ), strText );
  321.     wsprintf( strText, "%ld", js.lRy ); 
  322.     SetWindowText( GetDlgItem( hDlg, IDC_Y_ROT ), strText );
  323.     wsprintf( strText, "%ld", js.lRz ); 
  324.     SetWindowText( GetDlgItem( hDlg, IDC_Z_ROT ), strText );
  325.  
  326.     // For slider controls
  327.     wsprintf( strText, "%ld", js.rglSlider[0] ); 
  328.     SetWindowText( GetDlgItem( hDlg, IDC_SLIDER0 ), strText );
  329.     wsprintf( strText, "%ld", js.rglSlider[1] ); 
  330.     SetWindowText( GetDlgItem( hDlg, IDC_SLIDER1 ), strText );
  331.  
  332.     // Point of view
  333.     if( g_diDevCaps.dwPOVs >= 1 )
  334.     {
  335.         wsprintf( strText, "%ld", js.rgdwPOV[0] ); 
  336.         SetWindowText( GetDlgItem( hDlg, IDC_POV ), strText );
  337.     }
  338.  
  339.     // Fill up text with which buttons are pressed
  340.     str = strText;
  341.     for( int i = 0; i < 128; i++ )
  342.     {
  343.         if ( js.rgbButtons[i] & 0x80 )
  344.             str += wsprintf( str, "%02d ", i );
  345.     }
  346.     *str = 0;   // Terminate the string 
  347.  
  348.     SetWindowText( GetDlgItem( hDlg, IDC_BUTTONS ), strText );
  349.  
  350.     return S_OK;
  351. }
  352.  
  353.  
  354.  
  355.  
  356. //-----------------------------------------------------------------------------
  357. // Name: FreeDirectInput()
  358. // Desc: Initialize the DirectInput variables.
  359. //-----------------------------------------------------------------------------
  360. VOID FreeDirectInput()
  361. {
  362.     // Unacquire the device one last time just in case 
  363.     // the app tried to exit while the device is still acquired.
  364.     if( g_pJoystick ) 
  365.         g_pJoystick->Unacquire();
  366.     
  367.     // Release any DirectInput objects.
  368.     SAFE_RELEASE( g_pJoystick );
  369.     SAFE_RELEASE( g_pDI );
  370. }
  371.  
  372.  
  373.  
  374.